package game.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import common.model.po.Test;
import game.mapper.TestMapper;
import game.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 物品（包括零件和设备两类）服务实现类
 *
 * @author 米泽鹏
 * @since 2022-02-26
 */
@Slf4j
@Service
public class TestServiceImpl extends ServiceImpl<TestMapper, Test> implements TestService {

	/**
	 * 读取Excel中20W条数据到List耗时30秒
	 */
	@Override
	public void readLargeExcel() {
		long start = System.currentTimeMillis();
		List<Test> newRows = new ArrayList<>();
		ExcelUtil.readBySax("D:\\Administrator\\桌面\\test.xlsx", 0, (sheetIndex, rowIndex, rowCells) -> {
			if (rowIndex == 0) {
				return;
			}
			Test test = new Test();
			String idString = (String) rowCells.get(0);
			if (StrUtil.isNotBlank(idString)) {
				test.setId(Long.parseLong(idString));
			} else {
				test.setId(-1L);
			}
			test.setOperator((String) rowCells.get(1));
			test.setMethodName((String) rowCells.get(2));
			test.setMethodDescription((String) rowCells.get(3));
			test.setRequestUrl((String) rowCells.get(4));
			test.setIp((String) rowCells.get(5));
			test.setExecutionTime((Long) rowCells.get(6));
			test.setStatusCode(((Long) rowCells.get(7)).intValue());
			test.setMessage((String) rowCells.get(8));
			test.setExecutionDate((Date) rowCells.get(9));
			test.setCreateTime((Date) rowCells.get(10));
			test.setUpdateTime((Date) rowCells.get(11));
			newRows.add(test);
		});
		long end = System.currentTimeMillis();
		log.info("【读取Excel】数据总量：{}", newRows.size());
		log.info("【读取Excel】耗时：{}", end - start);
	}

	/**
	 * 查询20W条数据耗时3.4秒
	 */
	@Override
	public void largeQuery() {
		long start = System.currentTimeMillis();
		List<Test> rows = lambdaQuery().list();
		long end = System.currentTimeMillis();
		log.info("【查询】数据总量：{}", rows.size());
		log.info("【查询】耗时：{}", end - start);
	}

	/**
	 * 插入20W条数据耗时90秒
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void batchInsert() {
		long start = System.currentTimeMillis();
		List<Test> rows = new ArrayList<>();
		for (int i = 0; i < 200000; i++) {
			Test test = new Test();
			test.setOperator("name" + (i + 1));
			test.setMethodName("methodName" + (i + 1));
			test.setMethodDescription("methodDescription" + (i + 1));
			test.setRequestUrl("requestUrl" + (i + 1));
			test.setIp("IP" + (i + 1));
			test.setExecutionTime((long) i + 1);
			test.setExecutionDate(new Date());
			test.setStatusCode(200);
			test.setMessage("message" + (i + 1));
			rows.add(test);
		}
		saveBatch(rows, 10000);
		long end = System.currentTimeMillis();
		log.info("【批量插入】数据总量：{}", rows.size());
		log.info("【批量插入】耗时：{}", end - start);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void incrementalUpdate() {
		long start1 = System.currentTimeMillis();
		List<Test> newRows = new ArrayList<>();
		ExcelUtil.readBySax("D:\\Administrator\\桌面\\test.xlsx", 0, (sheetIndex, rowIndex, rowCells) -> {
			if (rowIndex == 0) {
				return;
			}
			Test test = new Test();
			String idString = (String) rowCells.get(0);
			if (StrUtil.isNotBlank(idString)) {
				test.setId(Long.parseLong(idString));
			} else {
				test.setId(-1L);
			}
			test.setOperator((String) rowCells.get(1));
			test.setMethodName((String) rowCells.get(2));
			test.setMethodDescription((String) rowCells.get(3));
			test.setRequestUrl((String) rowCells.get(4));
			test.setIp((String) rowCells.get(5));
			test.setExecutionTime((Long) rowCells.get(6));
			test.setStatusCode(((Long) rowCells.get(7)).intValue());
			test.setMessage((String) rowCells.get(8));
			test.setExecutionDate((Date) rowCells.get(9));
			test.setCreateTime((Date) rowCells.get(10));
			test.setUpdateTime((Date) rowCells.get(11));
			newRows.add(test);
		});
		long end1 = System.currentTimeMillis();
		log.info("【读取Excel】数据总量：{}", newRows.size());
		log.info("【读取Excel】耗时：{}", end1 - start1);

		long start2 = System.currentTimeMillis();
		List<Test> oldRows = lambdaQuery().list();
		long end2 = System.currentTimeMillis();
		log.info("【查询】数据总量：{}", oldRows.size());
		log.info("【查询】耗时：{}", end2 - start2);

		long start3 = System.currentTimeMillis();
		Map<Long, List<Test>> oldMap = oldRows.parallelStream().collect(Collectors.groupingBy(Test::getId));
		Map<Long, List<Test>> newMap = newRows.parallelStream().collect(Collectors.groupingBy(Test::getId));
		long end3 = System.currentTimeMillis();
		log.info("【分组】数据总量：{}", oldMap.size() + newMap.size());
		log.info("【分组】耗时：{}", end3 - start3);

		long start4 = System.currentTimeMillis();
		List<Test> updateList = new ArrayList<>();
		List<Test> insertList = newMap.get(-1L);
		List<Test> deleteList = new ArrayList<>();
		for (Test newRow : newRows) {
			if (newRow.getId() != null && newRow.getId() != -1L) {
				Test old = oldMap.get(newRow.getId()).get(0);
				if (!newRow.equals(old)) {
					updateList.add(newRow);
				}
			}
		}
		for (Test oldRow : oldRows) {
			if (!newMap.containsKey(oldRow.getId())) {
				deleteList.add(oldRow);
			}
		}
		long end4 = System.currentTimeMillis();
		log.info("【数据比对】数据总量：{}", updateList.size() + insertList.size() + deleteList.size());
		log.info("【数据比对】耗时：{}", end4 - start4);

		long start5 = System.currentTimeMillis();
		if (!updateList.isEmpty()) {
			updateBatchById(updateList);
		}
		if (!insertList.isEmpty()) {
			saveBatch(insertList);
		}
		if (!deleteList.isEmpty()) {
			removeByIds(deleteList);
		}
		long end5 = System.currentTimeMillis();
		log.info("【数据新增】数据总量：{}", insertList.size());
		log.info("【数据更新】数据总量：{}", updateList.size());
		log.info("【数据删除】数据总量：{}", deleteList.size());
		log.info("【数据新增、更新、删除】耗时：{}", end5 - start5);

		log.info("接口总耗时：{}", end5 - start1);
	}

	@Override
	public void deleteOtherData() {
		lambdaUpdate().lt(Test::getId, 1724814236058103813L).remove();
		lambdaUpdate().gt(Test::getId, 1724814236058303812L).remove();
	}

}
